package com.punai.dataanalysis.epdatakb.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.punai.common.core.domain.BaseEntity;
import com.punai.common.core.domain.entity.EcoCompany;
import com.punai.common.core.domain.entity.EcoCompanyDept;
import com.punai.common.core.domain.entity.SysDept;
import com.punai.common.exception.ServiceException;
import com.punai.common.utils.DateUtil;
import com.punai.common.utils.NumberUtil;
import com.punai.dataanalysis.epdatakb.bo.*;
import com.punai.dataanalysis.epdatakb.constants.DataKbConstants;
import com.punai.dataanalysis.epdatakb.domain.DataAnalysisTjdwzyclfzqfycbbl;
import com.punai.dataanalysis.epdatakb.vo.DataAnalysisVo;
import com.punai.external.domain.PmCostAccountInfo;
import com.punai.external.mapper.PmCostAccountInfoMapper;
import com.punai.externalccb.constants.CCBConstants;
import com.punai.externalccb.domain.YdTime;
import com.punai.externalccb.mapper.YdCbfeeiteminfoStandardMapper;
import com.punai.externalccb.mapper.YdTimeMapper;
import com.punai.externalccb.selectbo.GroupFullFeeCbBo;
import com.punai.monthanalysis.sqliteDao.CostStructureCategoryRepository;
import com.punai.monthanalysis.sqlitedomain.CostStructureCategory;
import com.punai.prodatalibrary.domain.LibProject;
import com.punai.prodatalibrary.mapper.LibProjectMapper;
import com.punai.system.mapper.EcoCompanyDeptMapper;
import com.punai.system.mapper.EcoCompanyMapper;
import com.punai.system.mapper.SysDeptMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.punai.dataanalysis.epdatakb.mapper.DataAnalysisTjdwrgfzbnqfycbblMapper;
import com.punai.dataanalysis.epdatakb.domain.DataAnalysisTjdwrgfzbnqfycbbl;
import com.punai.dataanalysis.epdatakb.service.IDataAnalysisTjdwrgfzbnqfycbblService;

/**
 * 土建单位人工费占本年全费用成本比例Service业务层处理
 *
 * @author zxw_
 * @date 2023-04-20
 */
@Service
public class DataAnalysisTjdwrgfzbnqfycbblServiceImpl extends ServiceImpl<DataAnalysisTjdwrgfzbnqfycbblMapper, DataAnalysisTjdwrgfzbnqfycbbl> implements IDataAnalysisTjdwrgfzbnqfycbblService {
    @Autowired
    private DataAnalysisTjdwrgfzbnqfycbblMapper dataAnalysisTjdwrgfzbnqfycbblMapper;

    @Autowired
    private EcoCompanyMapper ecoCompanyMapper;
    @Autowired
    private EcoCompanyDeptMapper ecoCompanyDeptMapper;
    @Autowired
    private SysDeptMapper sysDeptMapper;
    @Autowired
    private LibProjectMapper libProjectMapper;
    @Autowired
    private YdTimeMapper ydTimeMapper;
    @Autowired
    private YdCbfeeiteminfoStandardMapper ydCbfeeiteminfoStandardMapper;
    @Autowired
    private PmCostAccountInfoMapper pmCostAccountInfoMapper;
    @Autowired
    private CostStructureCategoryRepository costStructureCategoryRepository;

    @Override
    public List<? extends BaseEntity> getDataList(DataAnalysisVo dataAnalysisVo) {

        List<CbsRgfGroupBo> group = getGroup(dataAnalysisVo);
        List<DataAnalysisTjdwrgfzbnqfycbbl> resultList = new ArrayList<>();
        BigDecimal tjAllTotal = BigDecimal.ZERO;
        BigDecimal azAllTotal = BigDecimal.ZERO;
        BigDecimal tjrgfAllTotal = BigDecimal.ZERO;
        BigDecimal azrgfAllTotal = BigDecimal.ZERO;
        for (CbsRgfGroupBo groupBo : group) {
            DataAnalysisTjdwrgfzbnqfycbbl tjdwclfzbmx = new DataAnalysisTjdwrgfzbnqfycbbl();
            tjdwclfzbmx.setId(IdUtil.fastUUID());
            tjdwclfzbmx.setDeptName(groupBo.getName());
            resultList.add(tjdwclfzbmx);

            List<CbsRgfGroupProBo> proBos = groupBo.getProBos();
            BigDecimal tjTotal = BigDecimal.ZERO;
            BigDecimal azTotal = BigDecimal.ZERO;
            BigDecimal tjrgfTotal = BigDecimal.ZERO;
            BigDecimal azrgfTotal = BigDecimal.ZERO;
            for (CbsRgfGroupProBo proBo : proBos) {
                String proId = proBo.getProId();
                List<Integer> ydIds = proBo.getYdTimes();
                List<String> tj = proBo.getTj();
                List<String> az = proBo.getAz();
                List<String> tjrgf = proBo.getTjrgf();
                List<String> azrgf = proBo.getAzrgf();
                if(CollUtil.isEmpty(ydIds)) {
                    continue;
                }
                if(CollUtil.isEmpty(tj) && CollUtil.isEmpty(az) && CollUtil.isEmpty(tjrgf) && CollUtil.isEmpty(azrgf)) {
                    continue;
                }

                List<GroupFullFeeCbBo> groupFullFeeCbBos = ydCbfeeiteminfoStandardMapper.selectCbRgfByProAndCbsCodes(proId, CCBConstants.CCB_TYPE.YDCBFX.getCode(),
                        ydIds, tj, az, tjrgf, azrgf);
                for (GroupFullFeeCbBo groupFullFeeCbBo : groupFullFeeCbBos) {
                    if (StrUtil.equals("tj", groupFullFeeCbBo.getType())) {
                        tjTotal = NumberUtil.add(tjTotal, groupFullFeeCbBo.getFee());
                    } else if (StrUtil.equals("az", groupFullFeeCbBo.getType())) {
                        azTotal = NumberUtil.add(azTotal, groupFullFeeCbBo.getFee());
                    } else if (StrUtil.equals("tjrgf", groupFullFeeCbBo.getType())) {
                        tjrgfTotal = NumberUtil.add(tjrgfTotal, groupFullFeeCbBo.getFee());
                    } else if (StrUtil.equals("azrgf", groupFullFeeCbBo.getType())) {
                        azrgfTotal = NumberUtil.add(azrgfTotal, groupFullFeeCbBo.getFee());
                    }
                }
            }


            tjdwclfzbmx.setTjCostFeeYearZb(tjTotal);
            tjdwclfzbmx.setAzCostFeeYearZb(azTotal);
            tjdwclfzbmx.setTjXmRgF(tjrgfTotal);
            tjdwclfzbmx.setTjXmRgFZb(NumberUtil.divideUseProportion(tjrgfTotal, tjTotal));
            tjdwclfzbmx.setAzXmRgF(azrgfTotal);
            tjdwclfzbmx.setAzXmRgFZb(NumberUtil.divideUseProportion(azrgfTotal, tjTotal));

            // 占比


            tjAllTotal = NumberUtil.add(tjAllTotal, tjTotal);
            azAllTotal = NumberUtil.add(azAllTotal, azTotal);
            tjrgfAllTotal = NumberUtil.add(tjrgfAllTotal, tjrgfTotal);
            azrgfAllTotal = NumberUtil.add(azrgfAllTotal, azrgfTotal);

        }
        // 合计
        BigDecimal allTotal = NumberUtil.add(tjAllTotal, azAllTotal);

        BigDecimal tjzb = NumberUtil.divideUseProportion(tjAllTotal, allTotal);
        BigDecimal azzb = NumberUtil.divideUseProportion(azAllTotal, allTotal);

        BigDecimal tjrgfzb = NumberUtil.divideUseProportion(tjrgfAllTotal, allTotal);
        BigDecimal azrgf = NumberUtil.divideUseProportion(azrgfAllTotal, allTotal);

        DataAnalysisTjdwrgfzbnqfycbbl hj = new DataAnalysisTjdwrgfzbnqfycbbl();
        hj.setDeptName("土建单位平均占比");
        hj.setTjCostFeeYearZb(tjzb);
        hj.setAzCostFeeYearZb(azzb);
        hj.setTjXmRgF(tjrgfAllTotal);
        hj.setTjXmRgFZb(tjrgfzb);
        hj.setAzXmRgF(azrgfAllTotal);
        hj.setAzXmRgFZb(azrgf);

        resultList.add(hj);
        return resultList;
    }


    private List<CbsRgfGroupBo> getGroup(DataAnalysisVo dataAnalysisVo) {

        List<CbsRgfGroupBo> result = new ArrayList<>();

        // 列出公司
        List<EcoCompany> companyList = ecoCompanyMapper.selectList(
                Wrappers.<EcoCompany>lambdaQuery()
                        .eq(EcoCompany::getType, "T")
                        .eq(EcoCompany::getStatus, "0")
        );

        if (CollUtil.isEmpty(companyList)) {
            throw new ServiceException("无统计部门!");
        }

        // 统计公司 map
        Map<String, String> companyIdAndNameMap = companyList.stream().collect(Collectors.toMap(EcoCompany::getId, EcoCompany::getCompanyName));

        Set<String> ecoComIds = companyIdAndNameMap.keySet();

        List<EcoCompanyDept> ecoCompanyDepts = ecoCompanyDeptMapper.selectList(
                Wrappers.<EcoCompanyDept>lambdaQuery()
                        .in(EcoCompanyDept::getCompanyId, ecoComIds)
        );

        Map<String, List<EcoCompanyDept>> ecoCompanyLinks = ecoCompanyDepts.stream().collect(Collectors.groupingBy(EcoCompanyDept::getCompanyId));


        if (CollUtil.isEmpty(ecoCompanyDepts)) {
            throw new ServiceException("无关联部门!");
        }

        // 统计公司与部门关系
        List<String> deptIds = ecoCompanyDepts.stream().map(EcoCompanyDept::getDeptId).collect(Collectors.toList());
        // 统计公司相关的部门
        List<SysDept> sysDepts = sysDeptMapper.selectList(
                Wrappers.<SysDept>lambdaQuery()
                        .in(SysDept::getDeptId, deptIds)
        );


        Map<Long, List<SysDept>> deptIdMap = sysDepts.stream().collect(Collectors.groupingBy(SysDept::getDeptId));

        List<String> deptVxIds = sysDepts.stream().map(SysDept::getWeChatComDepId).collect(Collectors.toList());

        // 部门跟项目的关系
        List<LibProject> libProjects = libProjectMapper.selectList(
                Wrappers.<LibProject>lambdaQuery()
                        .in(LibProject::getDeptId, deptVxIds)
        );

        if (CollUtil.isEmpty(libProjects)) {
            throw new ServiceException("无关联项目!");
        }

        Map<String, List<LibProject>> proDeptVxIdMap = libProjects.stream().collect(Collectors.groupingBy(LibProject::getDeptId));


        Map<String, String> codeIdMap = libProjects.stream().collect(Collectors.toMap(LibProject::getCode, LibProject::getId, (v1, v2) -> v2));

        Set<String> proCodes = codeIdMap.keySet();


        String startTime = dataAnalysisVo.getStartTime();
        String endTime = dataAnalysisVo.getEndTime();


        // systemTempl  新中大 cbs 置换成 pn cbs id
        List<CostStructureCategory> categoryList = costStructureCategoryRepository.findAll();

        if (CollUtil.isEmpty(categoryList)) {
            throw new ServiceException("");
        }

        List<PmCostAccountInfo> pmCostAccountInfos = pmCostAccountInfoMapper.selectList(
                Wrappers.<PmCostAccountInfo>lambdaQuery()
                        .in(PmCostAccountInfo::getPcno, proCodes)
        );


        Map<String, List<PmCostAccountInfo>> proCodeAndCbsMap = pmCostAccountInfos.stream().collect(Collectors.groupingBy(PmCostAccountInfo::getPcno));

        companyIdAndNameMap.forEach((k, v) -> {
            CbsRgfGroupBo groupBo = new CbsRgfGroupBo();
            groupBo.setName(v);
            List<EcoCompanyDept> ecoCompanyDepts1 = ecoCompanyLinks.get(k);
            if (CollUtil.isEmpty(ecoCompanyDepts1)) {
                result.add(groupBo);
                return;
            }
            for (EcoCompanyDept ecoCompanyDept : ecoCompanyDepts1) {
                String deptId = ecoCompanyDept.getDeptId();
                List<SysDept> sysDepts1 = deptIdMap.get(Long.parseLong(deptId));
                for (SysDept sysDept : sysDepts1) {
                    String weChatComDepId = sysDept.getWeChatComDepId();

                    List<LibProject> libProjects1 = proDeptVxIdMap.get(weChatComDepId);


                    for (LibProject libProject : libProjects1) {
                        CbsRgfGroupProBo groupProBo = new CbsRgfGroupProBo();

                        groupProBo.setProId(libProject.getId());

                        String code = libProject.getCode();
                        List<PmCostAccountInfo> pmCostAccountInfos1 = proCodeAndCbsMap.get(code);
                        if (CollUtil.isEmpty(pmCostAccountInfos1)) {
                            continue;
                        }
                        List<String> proUsedCbsIds = new ArrayList<>();
                        for (PmCostAccountInfo pmCostAccountInfo : pmCostAccountInfos1) {
                            proUsedCbsIds.add(pmCostAccountInfo.getCbscode());
                        }

                        List<String> tjRgf = getPnCbsId(categoryList, proUsedCbsIds, DataKbConstants.CBS_TABS_TYPE.TJ_RGF);
                        List<String> azRgf = getPnCbsId(categoryList, proUsedCbsIds, DataKbConstants.CBS_TABS_TYPE.AZ_RGF);


                        List<YdTime> ydTimes = ydTimeMapper.selectList(
                                Wrappers.<YdTime>lambdaQuery()
                                        .eq(YdTime::getProId, libProject.getId())
                                        .eq(YdTime::getStagetype, CCBConstants.CCB_TYPE.YDCBFX.getCode())
                                        .gt(StrUtil.isNotBlank(startTime),YdTime::getStartdate, DateUtil.getDate(startTime + "-01"))
                                        .lt(StrUtil.isNotBlank(endTime),YdTime::getStartdate, DateUtil.getDate(endTime + "-01"))
                        );
                        List<Integer> ydIds = ydTimes.stream().map(YdTime::getOid).collect(Collectors.toList());

                        groupProBo.setTj(tjRgf);
                        groupProBo.setAz(azRgf);
                        groupProBo.setTjrgf(tjRgf);
                        groupProBo.setAzrgf(azRgf);

                        groupProBo.setYdTimes(ydIds);
                        groupBo.getProBos().add(groupProBo);
                    }
                }
            }
            result.add(groupBo);
        });

        return result;
    }


    private List<String> getPnCbsId(List<CostStructureCategory> categoryList, List<String> proUsedCbsIds, DataKbConstants.CBS_TABS_TYPE cbsTabsType) {
        List<String> resultList = new ArrayList<>();
        CbsResBo cbsCodes = cbsTabsType.getRangeCbsCodes();
        List<String> include = cbsCodes.getInclude();
        List<String> exclude = cbsCodes.getExclude();

        for (CostStructureCategory category : categoryList) {
            String categoryCode = category.getCategoryCode();
            boolean flag = true;
            for (String excludeCode : exclude) {
                if (StrUtil.startWith(categoryCode, excludeCode, false)) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                for (String includeCode : include) {
                    // 不是排除的 并且 匹配到了前缀  并且 是项目使用到的
                    if (StrUtil.startWith(categoryCode, includeCode, false)
                            && proUsedCbsIds.contains(categoryCode)) {
                        resultList.add(category.getId());
                    }
                }
            }
        }
        return resultList;
    }
}
